<?php

  require_once "JooS/Server/Presentation.php";

  abstract class JooS_Server_Presentation_Abstract_Xsl extends JooS_Server_Presentation {
    const XMLNS = "http://joos.nnov.ru/xml";

    const XMLNS_XSL = "http://www.w3.org/1999/XSL/Transform";

    private $_resource;

    public function getBody($resource) {
      $this->_resource = $resource;
      $data = $this->getData();

      $document = new DOMDocument("1.0", ini_get("default_charset"));
      $this->traverseData($document, $data);

      $processor = @$this->getProcessor();
      $body = $processor->transformToXml($document);

      return $body;
    }

    public function getContentType() {
      return "application/xml";
    }

    protected function getResource() {
      return $this->_resource;
    }

    protected function getData() {
      return $this->getResource()->getData();
    }

    public function traverseData($element, $data) {
      $document = ($element->nodeType == XML_DOCUMENT_NODE ? $element : $element->ownerDocument);

      $child = null;
      if (is_array($data)) {
        if (isset($data[0])) {
          $tagName = is_numeric($data[0]) ? "item" : $data[0];

          $child = $document->createElementNS(self::XMLNS, $tagName);
          $element->appendChild($child);
          if (isset($data[1])) {
            if (is_object($data[1])) {
              foreach ($data[1] as $k => $v) {
                $attr = $document->createAttribute($k);
                $attr->value = $v;
                $child->appendChild($attr);
              }
              $firstChildIdx = 2;
            }
            else
              $firstChildIdx = 1;

            for ($i = $firstChildIdx; $i < sizeof($data); $i++)
              $this->traverseData($child, $data[$i]);
          }
          $child = null;
        }
      }
      else
        $child = $document->createCDATASection($data);

      if (!is_null($child))
        $element->appendChild($child);
    }

    protected function getProcessor() {
      $request = $this->getRequest();
      $xslFilename = trim($request->getResourcePath() . $request->getResourceAction(), "/") . ".xsl";

      $xslDocument = new DOMDocument("1.0", ini_get("default_charset"));
      $xslDocument->loadXML('<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="' . self::XMLNS_XSL . '" />');

      $this->appendTransformImports($xslDocument);
      $this->appendTransformOutput($xslDocument);
      $this->appendTransformIncludes($xslDocument);

      $proc = new XSLTProcessor();
      $proc->importStylesheet($xslDocument);
      
      return $proc;
    }

    /**
     *
     *  <xsl:import href="output.xsl" />
     *  <xsl:import href="xsl://presentation/{getPresentation()}.xsl" />
     *
     */
    protected function appendTransformImports($xslDocument) {
      require_once "JooS/Server/Stream/Xsl.php";

      $request = $this->getRequest();

      $presentation = $xslDocument->createElementNS(self::XMLNS_XSL, "xsl:import");
      $presentation->setAttribute("href", JooS_Server_Stream_Xsl::STREAM_PROTOCOL . "://presentation/" . $request->getResourcePresentation() . ".xsl");
      $xslDocument->documentElement->appendChild($presentation);

      $output = $xslDocument->createElementNS(self::XMLNS_XSL, "xsl:import");
      $output->setAttribute("href", JooS_Server_Stream_Xsl::STREAM_PROTOCOL . "://output.xsl");
      $xslDocument->documentElement->appendChild($output);
    }

    protected function getTransformOutputAttributes() {
      return array(
        "method" => "xml", 
        "indent" => "yes", 
      );
    }
    
    final protected function appendTransformOutput($xslDocument) {
      $output = $xslDocument->createElementNS(self::XMLNS_XSL, "xsl:output");
      $attr = $this->getTransformOutputAttributes();
      $attr["encoding"] = ini_get("default_charset");
      foreach ($attr as $k => $v)
        $output->setAttribute($k, $v);

      $xslDocument->documentElement->appendChild($output);
    }

    /**
     *
     * <xsl:include href="views/{getControllerName()}.xsl" />
     *
     */
    protected function appendTransformIncludes($xslDocument) {
      require_once "JooS/Server/Stream/Xsl.php";

      $controller = $this->getResource()->getController();
      $include = $xslDocument->createElementNS(self::XMLNS_XSL, "xsl:include");
      $include->setAttribute("href", JooS_Server_Stream_Xsl::STREAM_PROTOCOL . "://views/" . $controller->getControllerName() . ".xsl");

      $xslDocument->documentElement->appendChild($include);
    }
  }

?>